package com.bckj.fastboot.core.extra.retry;

import com.bckj.fastboot.core.jackson.JsonUtils;
import com.bckj.fastboot.core.util.SpringUtils;
import lombok.extern.slf4j.Slf4j;

import java.util.List;

@Slf4j
public abstract class AbstractRetryConsumer {

    public int consume(RetryContext retryContext) {
        if (retryContext.getRetryCount() > retryContext.getMaxRetryCount()) {
            log.info("重试次数耗尽, bizId=" + retryContext.getBizId());
            return 1;
        }
        try {
            // 执行业务逻辑
            doExec(retryContext);
            return 1; // 成功消费
        } catch (Exception e) {
            log.error("重试异常, bizId=" + retryContext.getBizId(), e);
            // 计算下次重试时间（示例：10s, 30s, 1m）
            long delaySeconds = calculateDelaySeconds(retryContext);
            retryContext.setRetryCount(retryContext.getRetryCount() + 1);
            retryContext.setExceptionMsg(e.getMessage());
            getRetryProducer().sendRetryMessage(retryContext, delaySeconds);
            return 1;
        }
    }

    private long calculateDelaySeconds(RetryContext retryContext) {
        int retryCount = retryContext.getRetryCount();
        if (retryContext.getMultiplier() == 0) {
            return retryContext.getInitialInterval();
        } else {
            return retryContext.getInitialInterval() * (long) Math.pow(retryContext.getMultiplier(), retryCount);
        }
    }

    private void doExec(RetryContext retryContext) {
        log.info("正在重试中...，bizId=" + retryContext.getBizId() + ", retryCount=" + retryContext.getRetryCount());
        String className = retryContext.getClassName();
        String methodName = retryContext.getMethodName();
        Object bean = SpringUtils.getBean(className);
        try {
            Class<?> clazz = Class.forName(className);
            List<String> strArgsTypes = retryContext.getArgTypes();
            Class<?>[] argTypes = new Class[retryContext.getArgTypes().size()];
            for (int i = 0; i < retryContext.getArgTypes().size(); i++) {
                argTypes[i] = Class.forName(strArgsTypes.get(i));
            }
            List<String> strArgs = retryContext.getArgs();
            Object[] args = new Object[strArgs.size()];
            for (int i = 0; i < strArgs.size(); i++) {
                args[i] = JsonUtils.toBean(strArgs.get(i), argTypes[i]);
            }
            Object arg0 = args[0];
            if (arg0 instanceof FastRetryParam retryParam) {
                retryParam.setRetryCount(retryContext.getRetryCount());
            }
            java.lang.reflect.Method method = clazz.getMethod(methodName, argTypes);
            method.invoke(bean, args);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public abstract RetryProducer getRetryProducer();
}
